/* 
vue3全局自定义指令流程:
1.创建directive文件夹,和对应的ts文件
2.导入vue的类型接口 import { App } from 'vue'
3.默认暴露一个对象
4.对象一个install方法,第一个参数就是app(这就是vue原型),类型是上面导入的App类型
5.app.directive配置自定义指令
6.const myDirective = {
  // 在绑定元素的 attribute 前
  // 或事件监听器应用前调用
  created(el, binding, vnode, prevVnode) {
    // 下面会介绍各个参数的细节
  },
  // 在元素被插入到 DOM 前调用
  beforeMount(el, binding, vnode, prevVnode) {},
  // 在绑定元素的父组件
  // 及他自己的所有子节点都挂载完成后调用
  mounted(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件更新前调用
  beforeUpdate(el, binding, vnode, prevVnode) {},
  // 在绑定元素的父组件
  // 及他自己的所有子节点都更新后调用
  updated(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件卸载前调用
  beforeUnmount(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件卸载后调用
  unmounted(el, binding, vnode, prevVnode) {}
}
7.把该文件导入到main.ts,用app.use(directive文件)挂载即可全局使用
import directive from './directive'
app.use(directive)
*/

import { App } from 'vue'
import headJpg from '@/assets/common/head.jpg'
import { useIntersectionObserver } from '@vueuse/core'
import defaultImg from '@/assets/common/error.webp'
let clickOutFn: any
export default {
  install(Vue: App) {
    Vue.directive('imgError', {
      mounted(el, binding) {
        el.src = el.src || binding.value || headJpg
        el.onerror = function () {
          console.log('报错')
          el.src = binding.value || headJpg
        }
      },
      updated(el, binding) {
        el.src = el.src || binding.value || headJpg
        el.onerror = function () {
          el.src = binding.value || headJpg
        }
      }
    })
    /* 
    图片懒加载技术: 在滚动到可视区域时才加载图片
    原理: 利用@vueuse/core插件,在图片可见时,才会赋予图片src值
    流程:
      1.下载插件 npm i @vueuse/core
      2.封装自定义指令(多次复用,节省代码)
        import { useIntersectionObserver } from '@vueuse/core' // 导入插件的解构方法
        import defaultImg from '@/assets/common/error.webp' // 图片加载不出来显示的图片

        Vue.directive('imglazy', {
          mounted (el, binding) {
            // 判断 el(DOM)元素 是否出现在可视区域
            let { stop } = useIntersectionObserver(el, ([{ isIntersecting }]) => {
              if (isIntersecting) {
                // 说明出现在可视区域,就将地址赋值给 src
                el.src = binding.value
                // 判断图片是否加载不出来
                el.onerror = function () {
                  el.src = defaultImg
                }
                // 一旦图片设置成功，我们就将判断结束
                stop()
              }
            })
          }
        })

    */
    Vue.directive('imglazy', {
      // DOM元素挂载时触发
      mounted(el, binding) {
        // 判断 el(DOM元素) 是否出现在可视区域
        // 解构出stop方法,用来解除DOM元素身上的可见事件
        // 该方法的第一个参数是DOM元素,第二个参数是回调函数,参数是布尔值
        // 布尔值如果是true表示DOM元素显示了,然后我们赋予img的src值才加载图片
        const { stop } = useIntersectionObserver(el, ([{ isIntersecting }]) => {
          if (isIntersecting) {
            // 说明出现在可视区域,就将地址赋值给 src
            el.src = binding.value
            // 判断图片是否加载不出来
            el.onerror = function () {
              el.src = defaultImg
            }
            // 一旦图片设置成功，我们就将判断结束
            stop()
          }
        })
      }
    })
    // 判断点击元素是否在绑定的元素内的方法,不是就执行bind.value的方法(核心是contains方法)
    Vue.directive('clickOut', {
      mounted(el, binding) {
        clickOutFn = (e: any) => {
          // contains方法,在DOM元素用可以判断括号里的DOM元素在不在测验的DOM元素内
          if (el.contains(e.target)) {
            console.log('dom内')
          } else {
            console.log('dom外')
            // binding.value最好是一个函数,这样才会符合条件才会执行该函数,
            // 如果是直接执行的代码(比如showTree.value = false),
            // 会造成这行代码绑定自定义指令元素在就一直执行
            binding.value()
          }
        }
        document.addEventListener('click', clickOutFn)
      },
      beforeUnmount() {
        document.removeEventListener('click', clickOutFn)
      }
    })
  }
}
